// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <memory>
#include <optional>
#include <regex>
#include <string>
#include <string_view>
#include <vector>

#include "coin2/base/string_util.h"
#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/base/symbology/util.h"
#include "coin2/exchange/btcturk/symbology/currency.h"

namespace coin2::exchange::btcturk::symbology {

class BtcturkProduct : public base::symbology::SpotProduct<BtcturkCurrency, BtcturkProduct>,
                       public base::symbology::ProductFromStrMixin<BtcturkProduct> {
 public:
  typedef SpotProduct<BtcturkCurrency, BtcturkProduct> BaseProduct;

  BtcturkProduct(const BtcturkCurrency& base, const BtcturkCurrency& quote)
      : SpotProduct(
            base,
            quote,
            ToBtcturkNativeProduct(base, quote),
            ToBtcturkNativeProduct(base, quote),
            base::market::ExchangeType::Btcturk) {}

 public:
  static std::unique_ptr<BtcturkProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    std::unique_ptr<BtcturkCurrency> base_ptr;
    std::unique_ptr<BtcturkCurrency> quote_ptr;
    bool success =
        ParseBtcturkNativeProduct(native_product, resolve_timestamp, &base_ptr, &quote_ptr);
    if (success) {
      return std::make_unique<BtcturkProduct>(*base_ptr, *quote_ptr);
    } else {
      return {};
    }
  }

 private:
  static bool ParseBtcturkNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp,
      std::unique_ptr<BtcturkCurrency>* base_ptr,
      std::unique_ptr<BtcturkCurrency>* quote_ptr) {
    std::string base_str;
    std::string quote_str;

    static const std::regex reg("([A-Z0-9]{1,12})(_?)(TRY|BTC|USDT)");
    std::smatch match;
    bool res = std::regex_match(product_str, match, reg);
    if (!res){
      return false;
    }

    std::string base = match[1];
    std::string quote = match[3];

    *base_ptr = BtcturkCurrency::FromNativeStrNoThrow(base, resolve_timestamp);
    *quote_ptr = BtcturkCurrency::FromNativeStrNoThrow(quote, resolve_timestamp);
    return true;
  }

  static std::string ToBtcturkNativeProduct(
      const BtcturkCurrency& base,
      const BtcturkCurrency& quote) {
    using base::market::MarketType;
    return base.native_currency(MarketType::Spot) + quote.native_currency(MarketType::Spot);
  }
};

}  // namespace coin2::exchange::btcturk::symbology
